#include "dp_pthread.h"

// 上报线程
void *report_thread(void *arg)
{
    int param = *(int *)arg;
    free(arg);
    dp_node_p temp = (dp_node_p)((char *)dp + sizeof(int));
    int count = *(int *)dp;

    while (1)
    {
        cJSON *root = cJSON_CreateObject();
        cJSON_AddNumberToObject(root, "type", 1);
        cJSON_AddNumberToObject(root, "result", 0);
        cJSON *data_array = cJSON_CreateArray();

        for (int i = 0; i < count; i++)
        {
            bool changed = false;
            char val_str[32] = {0};

            switch (temp[i].type)
            {
            case 1: // bool
                if (param == 1 || param == 2 || temp[i].old_val.b_val != temp[i].new_val.b_val)
                {
                    changed = true;
                    snprintf(val_str, sizeof(val_str), "%d", temp[i].new_val.b_val ? 1 : 0);
                }
                break;
            case 2: // int
                if (param == 1 || param == 2 || temp[i].old_val.i_val != temp[i].new_val.i_val)
                {
                    changed = true;
                    snprintf(val_str, sizeof(val_str), "%d", temp[i].new_val.i_val);
                }
                break;
            case 3:                                                                                          // float
                if (param == 1 || param == 2 || fabsf(temp[i].old_val.f_val - temp[i].new_val.f_val) > 1e-6) // 防止浮点数误差，使用容差比较
                {
                    changed = true;
                    snprintf(val_str, sizeof(val_str), "%.2f", temp[i].new_val.f_val);
                }
                break;
            default:
                break;
            }

            if (changed)
            {
                cJSON *item = cJSON_CreateObject();
                cJSON_AddNumberToObject(item, "key", temp[i].key);
                cJSON_AddStringToObject(item, "val", val_str);
                cJSON_AddItemToArray(data_array, item);
                temp[i].old_val = temp[i].new_val; // 仅在有变化或主动上报时更新
            }
        }

        if (param == 1 || param == 3 || (param == 2 && cJSON_GetArraySize(data_array) > 0))
        {
            cJSON_AddItemToObject(root, "data", data_array);
            char *json_str = cJSON_Print(root);
            publishToQt(json_str);
            free(json_str);
        }
        else
        {
            cJSON_Delete(data_array);
        }

        cJSON_Delete(root);

        if (param == 1) // 刷新上报一次
            break;
        else
            sleep(period);
    }

    return NULL;
}

// 元宇宙上报线程
void *aiot_report_thread(void *arg)
{
    dp_node_p temp = (dp_node_p)((char *)dp + sizeof(int));
    int count = *(int *)dp;
    printf("open\n");
    while (1)
    {
        cJSON *root = cJSON_CreateObject();
        bool has_change = false;

        for (int i = 0; i < count; i++)
        {
            bool changed = false;

            switch (temp[i].type)
            {
            case 1: // bool
                cJSON_AddBoolToObject(root, key_to_name(temp[i].key), temp[i].new_val.b_val);
                break;
            case 2: // int
                cJSON_AddNumberToObject(root, key_to_name(temp[i].key), temp[i].new_val.i_val);
                break;
            case 3: // float
                cJSON_AddNumberToObject(root, key_to_name(temp[i].key), temp[i].new_val.f_val);
                break;
            default:
                break;
            }
        }

        char *json_str = cJSON_PrintUnformatted(root);
        publishToAito(json_str);
        free(json_str);
        cJSON_Delete(root);
        sleep(1);
    }

    return NULL;
}

const char *key_to_name(int key)
{
    switch (key)
    {
    case 309:
        return "co2";
    case 310:
        return "light";
    case 302:
        return "tem";
    case 303:
        return "hum";
    case 311:
        return "flame";
    case 312:
        return "infrared";
    case 304:
        return "fan";
    case 308:
        return "alarm";
    case 307:
        return "lamp";
    case 306:
        return "warmer";
    case 305:
        return "cooler";
    default:
        return "unknown";
    }
}

// 存储线程
void *storage_thread(void *arg)
{
    while (1)
    {
        dp_node_p temp = (dp_node_p)((char *)dp + sizeof(int)); // 获取起始地址
        int count = *(int *)dp;

        for (int i = 0; i < count; i++)
        {
            int result = insert_data_to_db(temp[i].key, temp[i].type, temp[i].new_val, time(NULL));
            if (result != 0)
            {
                fprintf(stderr, "写入数据库失败:key=%d\n", temp[i].key);
            }
        }

        sleep(120); // 每两分钟存储一次
    }
}

// 指令处理线程
void *command_handler_thread(void *arg)
{
    // 获取共享内存指针，去掉起始地址计数区域
    dp_node_p temp = (dp_node_p)((char *)dp + sizeof(int));

    cJSON *type = cJSON_GetObjectItem((cJSON *)arg, "type");
    // 根据传输的JSON的type值决定事务类型
    switch (type->valueint)
    {
    case 1: // 1：采集指令/采集回复指令
    {
        pthread_t p1;
        int *param = malloc(sizeof(int));
        *param = 1;
        pthread_create(&p1, NULL, report_thread, (void *)param);
        break;
    }
    case 2: // 2：控制指令/控制回复指令
    {
        dp_node_p cur = temp;
        cJSON *data = cJSON_GetObjectItem((cJSON *)arg, "data");
        cJSON *key = cJSON_GetObjectItem(data, "key");
        cJSON *val = cJSON_GetObjectItem(data, "val");
        int i = 0;
        for (i; i < *(int *)dp; i++)
        {
            if (cur->key == key->valueint)
                break;
            cur++;
        }
        if (i >= *(int *)dp)
        {
            printf("key not found\n");
            break;
        }

        con_t con = {
            .dev_type = cur->dev_type,
            .key = key->valueint};
        switch (cur->type)
        {
        case 1:
            con.val.b_val = atoi(val->valuestring);
            break;
        case 2:
            con.val.i_val = atoi(val->valuestring);
            break;
        case 3:
           con.val.f_val = ((int)(atof(val->valuestring) * 100 + 0.5)) / 100.0; //保留两位小数
            break;
        default:
            break;
        }
        if (msg_queue_send("control", &con, sizeof(con), IPC_NOWAIT) < 0)
        {
            printf("msg_queue_send failed\n");
        }
        else
        {
            printf("msg_queue_send ok\n");
        }
        break;
    }
    case 3: // 模式修改
    {       // 1. 解析客户端传入的 JSON 参数
        cJSON *arg_obj = (cJSON *)arg;
        cJSON *cmd_data = cJSON_GetObjectItem(arg_obj, "data");
        if (!cmd_data)
        {
            printf("指令格式错误：缺少 data 字段\n");
            break;
        }

        cJSON *type_item_in = cJSON_GetObjectItem(cmd_data, "type");
        if (!type_item_in)
        {
            printf("指令格式错误：缺少 type 字段\n");
            break;
        }

        int new_type = type_item_in->valueint;
        cJSON *period_item_in = cJSON_GetObjectItem(cmd_data, "period");
        int new_period = period_item_in ? period_item_in->valueint : 0;

        // 2. 读取配置文件
        FILE *fp = fopen("/home/wyq/bgp/upload/resources/node.json", "r");
        if (!fp)
        {
            printf("配置文件打开失败\n");
            break;
        }
        fseek(fp, 0, SEEK_END);
        long size = ftell(fp);
        rewind(fp);

        char *file_data = malloc(size + 1);
        if (!file_data)
        {
            fclose(fp);
            printf("内存分配失败\n");
            break;
        }
        fread(file_data, 1, size, fp);
        file_data[size] = '\0';
        fclose(fp);

        cJSON *file_root = cJSON_Parse(file_data);
        free(file_data);
        if (!file_root)
        {
            printf("配置 JSON 解析失败\n");
            pthread_exit("error");
        }

        cJSON *report_obj = cJSON_GetObjectItem(file_root, "report");
        if (!report_obj)
        {
            report_obj = cJSON_CreateObject();
            cJSON_AddItemToObject(file_root, "report", report_obj);
        }

        // 3. 设置 type 字段
        cJSON *type_field = cJSON_GetObjectItem(report_obj, "type");
        cJSON_ReplaceItemInObject(report_obj, "type", cJSON_CreateNumber(new_type));

        // 4. 设置period 字段
        if (new_type == 2)
        {
            cJSON *period_field = cJSON_GetObjectItem(report_obj, "period");
            if (period_field)
            {
                period_field->valueint = new_period;
            }
            else
            {
                cJSON_AddNumberToObject(report_obj, "period", new_period);
            }
        }

        // 5. 写回 JSON 文件
        char *new_json_str = cJSON_Print(file_root);
        FILE *fpw = fopen("/home/wyq/bgp/upload/resources/node.json", "w");
        if (!fpw)
        {
            printf("配置文件写入失败\n");
            free(new_json_str);
            cJSON_Delete(file_root);
            break;
        }
        fwrite(new_json_str, 1, strlen(new_json_str), fpw);
        fclose(fpw);
        printf("配置文件已更新\n");

        free(new_json_str);
        cJSON_Delete(file_root);
        break;
    }
    case 4: // 4：历史数据查询
    {
        cJSON *data = cJSON_GetObjectItem((cJSON *)arg, "data");
        if (!data)
        {
            printf("历史查询失败：缺少 data 字段\n");
            break;
        }

        cJSON *key = cJSON_GetObjectItem(data, "key");

        time_t start_ts = 0;
        time_t end_ts = time(NULL); // 默认到当前时间

        if (cJSON_HasObjectItem(data, "limit"))
        {
            cJSON *limit = cJSON_GetObjectItem(data, "limit");
            if (limit && limit->type == cJSON_Array && cJSON_GetArraySize(limit) == 2)
            {
                start_ts = cJSON_GetArrayItem(limit, 0)->valueint;
                end_ts = cJSON_GetArrayItem(limit, 1)->valueint;
            }

            else
            {
                printf("limit 字段格式错误,应为长度为2的数组\n");
                break;
            }
        }
        else
        {
            // 默认查询最近1小时数据
            start_ts = end_ts - 3600;
        }

        // 查询数据库
        cJSON *result = search_data_to_json(key->valueint, start_ts, end_ts);
        if (result)
        {
            cJSON_AddNumberToObject(result, "type", 4);
            char *json_str = cJSON_Print(result);
            publishToQt(json_str);
            free(json_str);
        }
        cJSON_Delete(result);
        break;
    }
    default:
        // 指令错误，返回错误代码
        break;
    }

    return NULL;
}
